package assister;

import java.util.Arrays;
import java.util.Vector;

/**rappresenta una classe che offre dei servizi ulteriori per gestire i tipi 
 * CLass<?
 * 
 * @author koldar
 * @version 1.0
 */
public class ClassAssister {

	/**ritorna TRUE se la classe <tt>son</tt> e' figlia della classe father; FALSE altrimenti.
	 * Superclass ritorna TRUE anche se son e' figlia indiretta di father; per esempio se 
	 * per ereditarieta' si ha che:
	 * <ul>
	 *  <li>A e' figlia di B</li>
	 *  <li>B e' figlia di C</li>
	 * </ul>
	 * allora invocare: <tt>isSuperclass(C,A)</tt> ritornera' TRUE.
	 * <p>Inoltre isSuperclass ritornera' FALSE se si impone che son e' uguale a father. isSuperclass non
	 * funziona per tutte le istanze di Class<?>: per tutte quelle istanze rappresentanti tipi primitivi
	 * o interfacce, isSuperclass non dara' risultati coerenti. Per le interfacce e' meglio usare isSuperInterface()
	 *  
	 * @param father la classe che si pensa essere un antenato di son
	 * @param son la classe che si pensa essere un discendente di father
	 * @return TRUE se father e' superclasse (anche indiretta) di son
	 */
	public static boolean isSuperclass(Class<?> father,Class<?> son){
		if (son.getSuperclass()==null){
			return false;
		}
		return son.getSuperclass()==father?true:isSuperclass(father, son.getSuperclass());
	}
	
	/**ritorna TRUE se e solo se l'interfaccia <tt>soninterface</tt> e' un discendente
	 * dell'interfaccia <tt>fatherinterface</tt>. Bisogna ricordarsi che in genere
	 * un interfaccia puo' avere piu' discendenti e piu' padri.
	 * <p>il metodo ritorna FALSE se <tt>soninterface</tt>non e' figlia di <tt>fatherinterface</tt>,
	 * oppure soninterface e fatherinterface sono uguali. 
	 * 
	 * @param fatherinterface l'interfaccia padre
	 * @param soninterface l'interfaccia figlia
	 * @throws IllegalArgumentException in caso in cui soninterface non rappresenti un'interfaccia
	 * @return TRUE se son e' figlia di father
	 */
	public static boolean isSuperInterface(Class<?> fatherinterface, Class<?> soninterface){
		if (!soninterface.isInterface()){
			throw new IllegalArgumentException();
		}
		Class<?>[] interfaces=soninterface.getInterfaces();
		//DEBUG System.out.println(soninterface.getSimpleName()+": "+interfaces.length);
		if (interfaces.length==0){
			return false;
		}
		for (Class<?> superinterface:interfaces){//scandaglio le interfaccie che estende il figlio
			if (superinterface.equals(fatherinterface)){//se tra queste c'e il padre ho finito
				return true;
			}
			if (isSuperInterface(fatherinterface,superinterface)){//se tra i padri delle interfaccia che estende il figlio c'e' il padre ho finito
				return true;
			}
		}
		return false;
	}
	
	/**data una classe, ritorna tutte le interfacce che lei e tutti i suoi antenati,
	 * implementano.
	 * 
	 * @param thisclass la classe da cui estrarre ogni singola interfaccia implementata
	 * @return un Vector di Class rappresentanti le interfacce implementate
	 */
	public static Vector<Class<?>> getAllInterfaces(Class<?> thisclass){
		return getAllInterfaces(thisclass, new Vector<Class<?>>(0,1));
	}
	
	private static Vector<Class<?>> getAllInterfaces(Class<?> thisclass,Vector<Class<?>> precedentlist){
		Class<?> superclass=thisclass.getSuperclass();
		precedentlist.addAll(new Vector<Class<?>>(Arrays.asList(thisclass.getInterfaces())));
		return (superclass==null?precedentlist:getAllInterfaces(superclass,precedentlist));
	}
}
